package com.ciwong.mobilelib.widget.clipimage;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.ScaleGestureDetector.OnScaleGestureListener;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewTreeObserver;
import android.widget.ImageView;

/**
 * 头像缩放，移动，处理
 */
public class ClipZoomImageView extends ImageView implements
        OnScaleGestureListener, OnTouchListener,
        ViewTreeObserver.OnGlobalLayoutListener
{
    /**
     * 缩放的最大比例
     */
    public float SCALE_MAX = 4.0f;

    /**
     * 缩放的中间比例
     */
    private float SCALE_MID = 2.0f;

    /**
     * 初始化时的缩放比例，如果图片宽或高大于屏幕，此值将小于0
     */
    private float initScale = 1.0f;

    /**
     * 剪切框与图片之比，即缩放最小值
     */
    private float clipFrameWithImageScale;

    /**
     * 当视图变动时，用于初始化判断
     */
    private boolean once = true;

    /**
     * 用于存放矩阵的9个值
     */
    private final float[] matrixValues = new float[9];

    /**
     * 缩放的手势检测
     */
    private ScaleGestureDetector mScaleGestureDetector = null;

    /**
     * 用于图片操作
     */
    private final Matrix mScaleMatrix = new Matrix();

    /**
     * 当图片被压缩前，保存压缩前图片状态，用于恢复
     */
    private Matrix tmpScaleMatrix = new Matrix();

    /**
     * 用于双击检测
     */
    private GestureDetector mGestureDetector;

    /**
     * 自动缩放判断
     */
    private boolean isAutoScale;

    private int mTouchSlop;

    /**
     * 最后手势点的位置X坐标，用于图片平移时，计算平移长度
     */
    private float end_x;

    private float end_y;

    /**
     * 用于判断是否属于拖动行为
     */
    private boolean isCanDrag;

    /**
     * 最后接触屏幕的点的个数
     */
    private int lastPointerCount;

    /**
     * 剪切头像宽
     */
    private int clipFrameWidth;

    /**
     * 剪切头像高
     */
    private int clipFrameHeight;

    /**
     * 水平方向与View的边距
     */
    private int mHorizontalPadding;

    /**
     * 垂直方向与View的边距
     */
    private int mVerticalPadding;

    /**
     * 判断是否要重置图片
     */
    private boolean isReset = false;

    public ClipZoomImageView(Context context)
    {
        this(context, null);
    }

    public ClipZoomImageView(Context context, AttributeSet attrs)
    {
        super(context, attrs);

        setScaleType(ScaleType.MATRIX);
        initListener(context);
    }

    /**
     * 剪切框大小
     * 
     * @param clip_width
     *            剪切的宽
     * @param clip_height
     *            剪切的高
     */
    public void initClipFrameSize(int clip_width, int clip_height)
    {
        clipFrameWidth = clip_width;
        clipFrameHeight = clip_height;
    }

    public void initClipPadding(int v, int h)
    {
        mVerticalPadding = v;
        mHorizontalPadding = h;
    }

    /**
     * 剪切图片，返回剪切后的bitmap对象
     * 
     * @return
     */
    public Bitmap clip()
    {
        Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(),
                Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        draw(canvas);
        return Bitmap.createBitmap(bitmap, mHorizontalPadding,
                mVerticalPadding, clipFrameWidth, clipFrameHeight);
    }

    /**
     * 初化监听器
     * 
     * @param context
     */
    private void initListener(Context context)
    {
        mScaleGestureDetector = new ScaleGestureDetector(context, this);
        this.setOnTouchListener(this);
        mGestureDetector = new GestureDetector(context,
                new SimpleOnGestureListener()
                {
                    @Override
                    public boolean onDoubleTap(MotionEvent e)
                    {
                        if (isAutoScale == true)
                            return true;

                        resetMatrix();

                        float x = e.getX();
                        float y = e.getY();
                        if (getScale() < SCALE_MID)
                        {
                            ClipZoomImageView.this.postDelayed(
                                    new AutoScaleRunnable(SCALE_MID, x, y), 16);
                            isAutoScale = true;
                        }
                        else
                        {
                            ClipZoomImageView.this.postDelayed(
                                    new AutoScaleRunnable(initScale, x, y), 16);
                            isAutoScale = true;
                        }

                        return true;
                    }
                });
    }

    /**
     * 自动缩放的任务
     * 
     * @author zhy
     * 
     */
    private class AutoScaleRunnable implements Runnable
    {
        static final float BIGGER = 1.07f;

        static final float SMALLER = 0.93f;

        private float mTargetScale;

        private float tmpScale;

        /**
         * 缩放的中心
         */
        private float x;

        private float y;

        /**
         * 传入目标缩放值，根据目标值与当前值，判断应该放大还是缩小
         * 
         * @param targetScale
         */
        public AutoScaleRunnable(float targetScale, float x, float y)
        {
            this.mTargetScale = targetScale;
            this.x = x;
            this.y = y;
            if (getScale() < mTargetScale)
            {
                tmpScale = BIGGER;
            }
            else
            {
                tmpScale = SMALLER;
            }
        }

        @Override
        public void run()
        {
            // 进行缩放
            mScaleMatrix.postScale(tmpScale, tmpScale, x, y);
            checkBorder();
            setImageMatrix(mScaleMatrix);

            final float currentScale = getScale();
            // 如果值在合法范围内，继续缩放
            if (((tmpScale > 1f) && (currentScale < mTargetScale))
                    || ((tmpScale < 1f) && (mTargetScale < currentScale)))
            {
                ClipZoomImageView.this.postDelayed(this, 16);
            }
            else
            // 设置为目标的缩放比例
            {
                final float deltaScale = mTargetScale / currentScale;
                mScaleMatrix.postScale(deltaScale, deltaScale, x, y);
                checkBorder();
                setImageMatrix(mScaleMatrix);
                isAutoScale = false;
            }

        }
    }

    /**
     * 图片缩放动作 {@inheritDoc}
     */
    @Override
    public boolean onScale(ScaleGestureDetector detector)
    {
        // 当前图片的比例
        float scale = getScale();
        // 要缩放的图片比例
        float scaleFactor = detector.getScaleFactor();
        if (getDrawable() == null || scaleFactor == 1.0f)
            return true;
        // 当此次缩放量大于最大比例时,则放大到最大比例
        if (scaleFactor * scale > SCALE_MAX)
        {
            scaleFactor = SCALE_MAX / scale;
        }
        if (isDoZoomin(detector, scale, scaleFactor, SCALE_MAX))
        {
            return true;
        }
        else
        {
            doZoomOut(detector, scale, scaleFactor, clipFrameWithImageScale);
        }
        // normalScale(detector, scale, scaleFactor, SCALE_MAX,
        // clipFrameWithImageScale);
        return true;
    }

    // /**
    // * 正常缩放,不压缩图片
    // *
    // * @param detector
    // * @param scale
    // * 原图比例
    // * @param scaleFactor
    // * 最大的缩放量
    // * @param scaleMax
    // * 缩放到最大值
    // * @param scaleMin
    // * 缩放到最小值
    // */
    // private void normalScale(ScaleGestureDetector detector, float scale,
    // float scaleFactor, float scaleMax, float scaleMin)
    // {
    // /**
    // * 缩放的范围控制
    // */
    // if ((scale < scaleMax && scaleFactor > 1.0f)
    // || (scale > scaleMin && scaleFactor < 1.0f))
    // {
    // // 当此次缩放小于最小值时，则使用缩放到最小值
    // if (scaleFactor * scale < scaleMin)
    // {
    // scaleFactor = scaleMin / scale;
    // }
    // // 当此次缩放大于最大值时，则使用缩放到最大值
    // if (scaleFactor * scale > scaleMax)
    // {
    // scaleFactor = scaleMax / scale;
    // }
    // // 设置缩放比例
    // mScaleMatrix.postScale(scaleFactor, scaleFactor,
    // detector.getFocusX(), detector.getFocusY());
    // checkBorder();
    // setImageMatrix(mScaleMatrix);
    // }
    // }

    /**
     * 执行放大缩放
     * 
     * @param detector
     * @param scale
     *            原图比例
     * @param scaleFactor
     *            缩放量
     * @param scaleMax
     *            最大的缩放量
     * @return 当此时缩放为放大动作时，返回true,则不再执行缩小操作
     */
    private boolean isDoZoomin(ScaleGestureDetector detector, float scale,
            float scaleFactor, float scaleMax)
    {
        if (scale < scaleMax && scaleFactor > 1.0f)
        {
            resetMatrix();
            // 设置缩放比例
            mScaleMatrix.postScale(scaleFactor, scaleFactor,
                    detector.getFocusX(), detector.getFocusY());
            checkBorder();
            setImageMatrix(mScaleMatrix);
            return true;
        }
        return false;
    }

    /**
     * 执行缩小缩放
     * 
     * @param detector
     * @param scale
     *            原图比例
     * @param scaleFactor
     *            缩放量
     * @param scaleMin
     *            最小的缩放量
     */
    private void doZoomOut(ScaleGestureDetector detector, float scale,
            float scaleFactor, float scaleMin)
    {
        // 当此次缩小量小于最小比例时,保存图片被压缩前状态
        if (scaleFactor * scale < scaleMin && !isReset)
        {
            tmpScaleMatrix.set(mScaleMatrix);
        }
        // 计算控制此次缩放量,避免把全部图片缩放到剪切框里面
        RectF rectF = getMatrixRectF();
        float finalScaleX = scaleFactor;
        float finalScaleY = scaleFactor;
        float finalScaleWidth = rectF.width() * scaleFactor;
        float finalScaleHeigth = rectF.height() * scaleFactor;
        if (finalScaleWidth < clipFrameWidth)
        {
            finalScaleX = (clipFrameWidth * 1f - finalScaleWidth) * 1f
                    / (clipFrameWidth * 1f);
            finalScaleX = scaleFactor + finalScaleX;
            isReset = true;
        }
        if (finalScaleHeigth < clipFrameHeight)
        {
            finalScaleY = (clipFrameHeight * 1f - finalScaleHeigth) * 1f
                    / (clipFrameHeight * 1f);
            finalScaleY = scaleFactor + finalScaleY;
            isReset = true;
        }
        // 执行缩放
        mScaleMatrix.postScale(finalScaleX, finalScaleY, detector.getFocusX(),
                detector.getFocusY());
        checkBorder();
        setImageMatrix(mScaleMatrix);
    }

    /**
     * 当图片有被压缩时，调用此方法重置压缩前的图片
     * 
     * @return
     */
    private void resetMatrix()
    {
        if (isReset)
        {
            mScaleMatrix.set(tmpScaleMatrix);
            isReset = false;
        }
    }

    private int currentDegree = 0;

    public void turnLeft()
    {
        // currentDegree -= 90;
        RectF rect = getMatrixRectF();
        mScaleMatrix.postRotate(-90, rect.centerX(), rect.centerY());
        setImageMatrix(mScaleMatrix);
    }

    public void turnRight()
    {
        // currentDegree += 90;
        RectF rect = getMatrixRectF();
        mScaleMatrix.postRotate(90, rect.centerX(), rect.centerY());
        setImageMatrix(mScaleMatrix);
    }

    /**
     * 根据当前图片的Matrix获得图片的范围
     * 
     * @return RectF
     */
    private RectF getMatrixRectF()
    {
        Matrix matrix = mScaleMatrix;
        RectF rect = new RectF();
        Drawable d = getDrawable();
        if (null != d)
        {
            rect.set(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
            matrix.mapRect(rect);
        }
        return rect;
    }

    @Override
    public boolean onScaleBegin(ScaleGestureDetector detector)
    {
        return true;
    }

    @Override
    public void onScaleEnd(ScaleGestureDetector detector)
    {
    }

    @Override
    public boolean onTouch(View v, MotionEvent event)
    {
        // 双击缩放
        if (mGestureDetector.onTouchEvent(event))
        {
            return true;
        }
        // 手势缩放
        mScaleGestureDetector.onTouchEvent(event);
        // 平移
        imageTranslateCalculate(event);

        return true;
    }

    /**
     * 图片平移位置计算
     * 
     * @param event
     */
    private void imageTranslateCalculate(MotionEvent event)
    {
        float current_x = 0, current_y = 0;
        // 拿到触摸点的个数
        final int pointerCount = event.getPointerCount();
        // 得到多个触摸点的x与y均值
        for (int i = 0; i < pointerCount; i++)
        {
            current_x += event.getX(i);
            current_y += event.getY(i);
        }
        current_x = current_x / pointerCount;
        current_y = current_y / pointerCount;
        /**
         * 每当触摸点发生变化时，重置mLasX , mLastY
         */
        if (pointerCount != lastPointerCount)
        {
            isCanDrag = false;
            end_x = current_x;
            end_y = current_y;
        }
        lastPointerCount = pointerCount;

        switch (event.getAction())
        {
            case MotionEvent.ACTION_MOVE:
                float translate_dx = current_x - end_x;
                float translate_dy = current_y - end_y;
                imageDoTranslate(translate_dx, translate_dy);
                end_x = current_x;
                end_y = current_y;
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                lastPointerCount = 0;
                break;
        }
    }

    /**
     * 图片开始平移
     * 
     * @param translate_dx
     *            向X轴方向转移的长度
     * @param translate_dy
     *            向Y轴方向转移的长度
     */
    private void imageDoTranslate(float translate_dx, float translate_dy)
    {
        if (!isCanDrag)
        {
            isCanDrag = isCanDrag(translate_dx, translate_dy);
        }
        if (isCanDrag)
        {
            if (getDrawable() != null)
            {
                RectF rectF = getMatrixRectF();
                // 当原图的矩形的宽度小于等于剪切框的宽度时，X轴平移量为0
                if (rectF.width() <= clipFrameWidth)
                {
                    translate_dx = 0;
                }
                // 当原图的矩形的高度小于等于剪切框的高度时，Y轴平移量为0
                if (rectF.height() <= clipFrameHeight)
                {
                    translate_dy = 0;
                }
                mScaleMatrix.postTranslate(translate_dx, translate_dy);
                checkBorder();
                setImageMatrix(mScaleMatrix);
            }
        }
    }

    /**
     * 获得当前的缩放比例
     * 
     * @return
     */
    public final float getScale()
    {
        mScaleMatrix.getValues(matrixValues);
        float scale = Math.abs(matrixValues[0]);
        if (scale == 0)
        {
            scale = Math.abs(matrixValues[1]);
        }
        return scale;
    }

    @Override
    protected void onAttachedToWindow()
    {
        super.onAttachedToWindow();
        getViewTreeObserver().addOnGlobalLayoutListener(this);
    }

    @Override
    protected void onDetachedFromWindow()
    {
        super.onDetachedFromWindow();
        getViewTreeObserver().removeGlobalOnLayoutListener(this);
    }

    /**
     * 初始化原图
     */
    @Override
    public void onGlobalLayout()
    {
        if (once)
        {
            Drawable d = getDrawable();
            if (d == null)
                return;
            // 视图与图片的宽和高
            int viewWidth = getWidth();
            int viewHeight = getHeight();
            int dw = d.getIntrinsicWidth();
            int dh = d.getIntrinsicHeight();
            // 横向方向的边距
            mHorizontalPadding = (viewWidth - clipFrameWidth) / 2;
            // 垂直方向的边距
            mVerticalPadding = (viewHeight - clipFrameWidth) / 2;

            float scale = 1.0f;
            // 当原图宽度小于剪切框宽度且高度大于时，原图将以宽度倍数被放大到剪切宽
            if (dw < clipFrameWidth && dh > clipFrameHeight)
            {
                scale = clipFrameWidth * 1.0f / dw;
            }
            if (dh < clipFrameHeight && dw > clipFrameWidth)
            {
                scale = clipFrameHeight * 1.0f / dh;
            }
            // 原图宽高都小于剪切框时，将取最大的原图宽高比
            if (dw < clipFrameWidth && dh < clipFrameHeight)
            {
                float scaleW = clipFrameWidth * 1.0f / dw;
                float scaleH = clipFrameHeight * 1.0f / dh;
                scale = Math.max(scaleW, scaleH);
            }
            // 平移
            mScaleMatrix.postTranslate((viewWidth - dw) / 2,
                    (viewHeight - dh) / 2);
            // 以视图中心点为中心放大
            mScaleMatrix.postScale(scale, scale, getWidth() / 2,
                    getHeight() / 2);
            // 执行绘制
            setImageMatrix(mScaleMatrix);

            clipFrameWithImageScale = Math.max(clipFrameWidth * 1.0f / dw,
                    clipFrameHeight * 1.0f / dh);

            // 初始化
            initScale = scale;
            SCALE_MID = initScale * SCALE_MID;
            SCALE_MAX = initScale * SCALE_MAX;
            once = false;
        }
    }

    /**
     * 边界检测
     */
    private void checkBorder()
    {
        RectF rect = getMatrixRectF();
        float deltaX = 0;
        float deltaY = 0;

        int viewWidth = getWidth();
        int viewHeight = getHeight();
        if (rect.width() >= clipFrameWidth)
        {
            if (rect.left > mHorizontalPadding)
            {
                // 当前图片矩形的(left,x,x,x)大于剪切框的(left,x,x,x)时，则往反方向平移回多少
                deltaX = -rect.left + mHorizontalPadding;
            }
            if (rect.right < viewWidth - mHorizontalPadding)
            {
                deltaX = viewWidth - mHorizontalPadding - rect.right;
            }
        }
        if (rect.height() >= clipFrameHeight)
        {
            if (rect.top > mVerticalPadding)
            {
                deltaY = -rect.top + mVerticalPadding;
            }
            if (rect.bottom < viewHeight - mVerticalPadding)
            {
                deltaY = viewHeight - mVerticalPadding - rect.bottom;
            }
        }
        mScaleMatrix.postTranslate(deltaX, deltaY);
    }

    /**
     * 是否是拖动行为
     * 
     * @param dx
     * @param dy
     * @return
     */
    private boolean isCanDrag(float dx, float dy)
    {
        return Math.sqrt((dx * dx) + (dy * dy)) >= mTouchSlop;
    }
}
